#include "GameEngine.hpp"

#ifdef BASIC_REPRESENTATION
#include "BasicRepresentationEngine.hpp"
#else
#include "RealRepresentationEngine.hpp"
#endif

#include <iostream>

GameEngine::GameEngine(int argc, char** argv) {
    this->logicEngine = NULL;
    this->representationEngine = NULL;
}

GameEngine::~GameEngine() {
    if (this->logicEngine != NULL) {
        delete this->logicEngine;
    }

    if (this->representationEngine != NULL) {
        delete this->representationEngine;
    }
}

void GameEngine::executeCommand(string id) {
    if (id.compare("exit") == 0) {
        exit(0);
    }
    else if (id.compare("loadGame") == 0) {
        this->currentScene = this->loadScene(this->gameDataManager->loadGame());
        this->representationEngine->init(this->currentScene);
        this->logicEngine->init(this->currentScene, this->representationEngine->getElapsedTime());
        delete this->currentMenu;
        this->currentMenu = NULL;
    }
    else if (id.compare("newGame") == 0) {
        this->currentScene = this->loadScene(1);
        this->representationEngine->init(this->currentScene);
        this->logicEngine->init(this->currentScene, this->representationEngine->getElapsedTime());
        delete this->currentMenu;
        this->currentMenu = NULL;
    }
    else if (id.compare("openMainMenu") == 0) {
        this->logicEngine->end();
        delete this->currentScene;
        this->currentScene = NULL;
        this->currentMenu = new MainMenu(this->gameDataManager->gameDataExists());
        this->representationEngine->init(this->currentMenu);
    }
    else if (id.compare("restartLevel") == 0) {
        this->logicEngine->end();
        delete this->currentScene;
        this->currentScene = this->loadScene(this->currentSceneNumber);
        this->representationEngine->init(this->currentScene);
        this->logicEngine->init(this->currentScene, this->representationEngine->getElapsedTime());
        delete this->currentMenu;
        this->currentMenu = NULL;
    }
    else if (id.compare("resume") == 0) {
        this->logicEngine->setLastTime(this->representationEngine->getElapsedTime());
        delete this->currentMenu;
        this->currentMenu = NULL;
    }
    else if (id.compare("saveGame") == 0) {
        this->gameDataManager->saveGame(this->currentSceneNumber);
        this->executeCommand("resume");
    }
}

void GameEngine::handleKey(unsigned char key) {
    this->controlManager->keyDown(key);
}

void GameEngine::handleKeyUp(unsigned char key) {
    this->controlManager->keyUp(key);
}

void GameEngine::handleMouseButtonDown(int button) {
    this->controlManager->mouseButtonDown(button);
}

void GameEngine::handleMouseButtonUp(int button) {
    this->controlManager->mouseButtonUp(button);
}

void GameEngine::handleSpecialKey(int key) {
    this->controlManager->specialKeyDown(key);
}

void GameEngine::handleSpecialKeyUp(int key) {
    this->controlManager->specialKeyUp(key);
}

void GameEngine::init() {
    this->controlManager = new ControlManager();
    this->gameDataManager = new GameDataManager();
    this->logicEngine = new LogicEngine(this->controlManager);

#ifdef BASIC_REPRESENTATION
    std::cout << "basic" << std::endl;
    this->representationEngine = new BasicRepresentationEngine(this);
#else
    std::cout << "normal" << std::endl;
    this->representationEngine = new RealRepresentationEngine(this);
#endif

    this->currentScene = NULL;
    this->currentMenu = new MainMenu(this->gameDataManager->gameDataExists());
    this->representationEngine->init(this->currentMenu);
    this->representationEngine->runMainLoop();
}

Scene* GameEngine::loadScene(int number) {
    this->currentSceneNumber = number;

    if (number == 1) {
        return new Scene01();
    }

    if (number == 2) {
        return new Scene02();
    }

    if (number == 3) {
        return new Scene03();
    }

    if (number == 4) {
        return new Scene04();
    }

    if (number == 5) {
        return new Scene05();
    }

    if (number == 6) {
        return new Scene06();
    }

    if (number == 7) {
        return new Scene07();
    }

    if (number == 8) {
        return new Scene08();
    }

    if (number == 9) {
        return new Scene09();
    }

    if (number == 10) {
        return new Scene10();
    }

    if (number == 11) {
        return new Scene11();
    }

    if (number == 12) {
        return new Scene12();
    }

    if (number == 13) {
        return new Scene13();
    }

    if (number == 14) {
        return new Scene14();
    }

    if (number == 15) {
        return new Scene15();
    }

    if (number == 16) {
        return new Scene16();
    }

    return new SandboxScene();
}

void GameEngine::render() {
    if (this->currentMenu != NULL) {
        this->representationEngine->render(this->currentMenu, this->currentScene);

        if (this->controlManager->menuPrevious()) {
            this->currentMenu->previous();
        }

        if (this->controlManager->menuNext()) {
            this->currentMenu->next();
        }

        if (this->controlManager->menuSelect()) {
            Menu::MenuEntry* entry = this->currentMenu->options->at(this->currentMenu->selectedOption);
            this->executeCommand(*entry->id);
        }

        if (this->controlManager->openMenu() && this->currentScene != NULL) {
            this->executeCommand("resume");
        }
    }
    else {
        if (this->controlManager->openMenu()) {
            this->currentMenu = new GameMenu();
            this->representationEngine->init(this->currentMenu);
        }

        if (this->controlManager->zoomIn()) {
            this->representationEngine->zoomIn();
        }

        if (this->controlManager->zoomOut()) {
            this->representationEngine->zoomOut();
        }

        this->logicEngine->render(this->currentScene, this->representationEngine->getElapsedTime());
        this->representationEngine->render(this->currentScene);

        if (this->logicEngine->isSceneCompleted()) {
            if (this->currentScene->room->roomNumber == 16) {
                this->executeCommand("openMainMenu");
            }
            else {
                delete this->currentScene;
                this->currentScene = this->loadScene(this->currentSceneNumber + 1);
                this->logicEngine->end();
                this->logicEngine->init(this->currentScene, this->representationEngine->getElapsedTime());
            }
        }
    }
}
